From e59c28743ac2a399ecd22360aaf7cbc9c2c72812 Mon Sep 17 00:00:00 2001 From: Paolo Borelli Date: Fri, 30 Aug 2013 22:32:42 +0200 Subject: [PATCH] Add a needs-attention child property to GtkStack The child property is watched by the StackSwicther which in turns sets a needs-attention css class on the corresponding button, so that the theme can for instance show a throbbing animation if one of the hidden pages needs the user attention. https://bugzilla.gnome.org/show_bug.cgi?id=707153 --- gtk/gtkstack.c | 31 ++++++++++++++++++++++++++++++- gtk/gtkstackswitcher.c | 41 +++++++++++++++++++++++++++++++++++++++++ gtk/gtkstylecontext.h | 11 +++++++++++ tests/teststack.c | 1 + 4 files changed, 83 insertions(+), 1 deletion(-) diff --git a/gtk/gtkstack.c b/gtk/gtkstack.c index 01e943e495..cee970ab28 100644 --- a/gtk/gtkstack.c +++ b/gtk/gtkstack.c @@ -82,7 +82,8 @@ enum CHILD_PROP_NAME, CHILD_PROP_TITLE, CHILD_PROP_ICON_NAME, - CHILD_PROP_POSITION + CHILD_PROP_POSITION, + CHILD_PROP_NEEDS_ATTENTION }; typedef struct _GtkStackChildInfo GtkStackChildInfo; @@ -92,6 +93,7 @@ struct _GtkStackChildInfo { gchar *name; gchar *title; gchar *icon_name; + gboolean needs_attention; }; typedef struct { @@ -416,6 +418,23 @@ gtk_stack_class_init (GtkStackClass *klass) P_("The index of the child in the parent"), -1, G_MAXINT, 0, GTK_PARAM_READWRITE)); + + /** + * GtkStack:needs-attention: + * + * Sets a flag specifying whether the child requires the user attention. + * This is used by the #GtkStackSwitcher to change the appearance of the + * corresponding button when a page needs attention and it is not the + * current one. + * + * Since: 3.12 + */ + gtk_container_class_install_child_property (container_class, CHILD_PROP_NEEDS_ATTENTION, + g_param_spec_boolean ("needs-attention", + P_("Needs Attention"), + P_("Whether this page needs attention"), + FALSE, + GTK_PARAM_READWRITE)); } /** @@ -548,6 +567,10 @@ gtk_stack_get_child_property (GtkContainer *container, g_value_set_int (value, i); break; + case CHILD_PROP_NEEDS_ATTENTION: + g_value_set_boolean (value, info->needs_attention); + break; + default: GTK_CONTAINER_WARN_INVALID_CHILD_PROPERTY_ID (container, property_id, pspec); break; @@ -615,6 +638,11 @@ gtk_stack_set_child_property (GtkContainer *container, reorder_child (stack, child, g_value_get_int (value)); break; + case CHILD_PROP_NEEDS_ATTENTION: + info->needs_attention = g_value_get_boolean (value); + gtk_container_child_notify (container, child, "needs-attention"); + break; + default: GTK_CONTAINER_WARN_INVALID_CHILD_PROPERTY_ID (container, property_id, pspec); break; @@ -1001,6 +1029,7 @@ gtk_stack_add (GtkContainer *container, child_info->name = NULL; child_info->title = NULL; child_info->icon_name = NULL; + child_info->needs_attention = FALSE; priv->children = g_list_append (priv->children, child_info); diff --git a/gtk/gtkstackswitcher.c b/gtk/gtkstackswitcher.c index b8e008e86d..0aa6204f84 100644 --- a/gtk/gtkstackswitcher.c +++ b/gtk/gtkstackswitcher.c @@ -68,6 +68,7 @@ gtk_stack_switcher_init (GtkStackSwitcher *switcher) priv->buttons = g_hash_table_new (g_direct_hash, g_direct_equal); context = gtk_widget_get_style_context (GTK_WIDGET (switcher)); + gtk_style_context_add_class (context, "stack-switcher"); gtk_style_context_add_class (context, GTK_STYLE_CLASS_LINKED); gtk_orientable_set_orientation (GTK_ORIENTABLE (switcher), GTK_ORIENTATION_HORIZONTAL); @@ -138,6 +139,25 @@ rebuild_child (GtkWidget *self, } } +static void +update_needs_attention (GtkWidget *widget, GtkWidget *button, gpointer *data) +{ + GtkContainer *container; + gboolean needs_attention; + GtkStyleContext *context; + + container = GTK_CONTAINER (data); + gtk_container_child_get (container, widget, + "needs-attention", &needs_attention, + NULL); + + context = gtk_widget_get_style_context (button); + if (needs_attention && !gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (button))) + gtk_style_context_add_class (context, GTK_STYLE_CLASS_NEEDS_ATTENTION); + else + gtk_style_context_remove_class (context, GTK_STYLE_CLASS_NEEDS_ATTENTION); +} + static void update_button (GtkStackSwitcher *self, GtkWidget *widget, @@ -165,6 +185,8 @@ update_button (GtkStackSwitcher *self, g_free (title); g_free (icon_name); + + update_needs_attention (widget, button, priv->stack); } static void @@ -201,6 +223,20 @@ on_position_updated (GtkWidget *widget, gtk_box_reorder_child (GTK_BOX (self), button, position); } +static void +on_needs_attention_updated (GtkWidget *widget, + GParamSpec *pspec, + GtkStackSwitcher *self) +{ + GtkWidget *button; + GtkStackSwitcherPrivate *priv; + + priv = gtk_stack_switcher_get_instance_private (self); + + button = g_hash_table_lookup (priv->buttons, widget); + update_button (self, widget, button); +} + static void add_child (GtkStackSwitcher *self, GtkWidget *widget) @@ -230,6 +266,7 @@ add_child (GtkStackSwitcher *self, g_signal_connect (widget, "child-notify::title", G_CALLBACK (on_title_icon_updated), self); g_signal_connect (widget, "child-notify::icon-name", G_CALLBACK (on_title_icon_updated), self); g_signal_connect (widget, "child-notify::position", G_CALLBACK (on_position_updated), self); + g_signal_connect (widget, "child-notify::needs-attention", G_CALLBACK (on_needs_attention_updated), self); g_hash_table_insert (priv->buttons, widget, button); } @@ -269,6 +306,10 @@ on_child_changed (GtkWidget *widget, gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), TRUE); priv->in_child_changed = FALSE; } + + g_hash_table_foreach (priv->buttons, + (GHFunc)update_needs_attention, + priv->stack); } static void diff --git a/gtk/gtkstylecontext.h b/gtk/gtkstylecontext.h index 29f3ebfab8..ed5f40da18 100644 --- a/gtk/gtkstylecontext.h +++ b/gtk/gtkstylecontext.h @@ -754,6 +754,17 @@ struct _GtkStyleContextClass */ #define GTK_STYLE_CLASS_TITLEBAR "titlebar" +/** + * GTK_STYLE_CLASS_NEEDS_ATTENTION: + * + * A CSS class used when an element needs the user attention, + * for instance a button in a stack switcher corresponding to + * a hidden page that changed state. +* + * Since: 3.12 + */ +#define GTK_STYLE_CLASS_NEEDS_ATTENTION "needs-attention" + /* Predefined set of widget regions */ /** diff --git a/tests/teststack.c b/tests/teststack.c index 3853af2ba2..e684d2378b 100644 --- a/tests/teststack.c +++ b/tests/teststack.c @@ -144,6 +144,7 @@ main (gint argc, gtk_container_child_set (GTK_CONTAINER (stack), w2, "name", "2", "title", "2", + "needs-attention", TRUE, NULL); -- 2.30.2